home *** CD-ROM | disk | FTP | other *** search
/ Cracking 2 / Cracking II..iso / Texty / crackme / Level2.txt < prev    next >
Encoding:
Text File  |  1998-05-11  |  9.3 KB  |  200 lines

  1. [ Cracking Level-2  Making Your First Key Generator ]
  2. =====================================================
  3.  
  4. First off, there are two ways to make a key generator.  First type 
  5. is to copy the entire assembly code, modify it a little to make it
  6. produce the key, and compile it using an assembler.  In this case
  7. you'll only need to know where the registration code starts, where
  8. it ends, and what are its variables.  Second type is to analysis
  9. the entire registration routine, and translate/modified it into a 
  10. higher level language, and compile it using high level language 
  11. compiler.  This will take a little bit longer, but I perfer to write
  12. key makers this way.  As it is how I write all my other key makers.
  13.  
  14. Below is a main portion of the Level-2 registration routine obtained
  15. from W32Dasm.  I have heavily commented the code to make things clear
  16. and to help you learn Assembly language along the way.
  17.  
  18. Go break into the program, set a break point on GetDlgItemTextA
  19. And once you're in press [F12] to get out from USER32 and MFC42, until
  20. you get back into CrackMe's instruction codes.  Once you're in
  21. CrackMe, try and get to the first line [F10] shown below (:00401ADF).
  22. Note that you might still have the break point on GetDlgItemTextA, so
  23. you might want to disable that before stepping trought the codes.
  24. "d *" is the command to disable all break points in Softice.
  25.  
  26. ----------------------------------------------------------------------
  27. :00401ADF E8FA100000      Call 00402BDE  ; MFC42.GetDlgItemTextA
  28. :00401AE4 8D4C247C        lea ecx, dword ptr [esp+7C]
  29. :00401AE8 6A33            push 00000033
  30. :00401AEA 51              push ecx
  31. :00401AEB 68ED030000      push 000003ED
  32. :00401AF0 8BCB            mov ecx, ebx
  33. :00401AF2 E8E7100000      Call 00402BDE  ; MFC42.GetDlgItemTextA  (get username)
  34. :00401AF7 8D542414        lea edx, dword ptr [esp+14] ; -> points to username
  35. :00401AFB 52              push edx  ; -> push username on stack for lstrlenA
  36. :00401AFC FF1500404000    Call dword ptr [00404000]  ; KERNEL32.lstrlenA
  37. :00401B02 8BF0            mov esi, eax  ; save string length to esi
  38. :00401B04 83FE05          cmp esi, 00000005  ; is string length < 5 ?
  39. :00401B07 7311            jnb 00401B1A  ; jump/good name if length is >= 5
  40. :00401B09 6A40            push 00000040
  41. :00401B0B 6804514000      push 00405104
  42. :00401B10 68D8504000      push 004050D8
  43. :00401B15 E9BA000000      jmp 00401BD4  ; jump/quit to show end MessageBox
  44.  
  45. :00401B1A B801000000      mov eax, 00000001  ; set eax to 1 (counter)
  46. :00401B1F 33FF            xor edi, edi  ; set edi to 0
  47. :00401B21 3BF0            cmp esi, eax  ; (esi - eax)
  48. :00401B23 7211            jb 00401B36   ; jump if esi(length) < eax;
  49.  
  50.                           ; [esp+14] points to the username
  51.                           ; eax is the counter
  52. :00401B25 0FBE4C0414      movsx ecx, byte ptr [esp+eax+14] ; ecx = user[eax]
  53. :00401B2A 03CF            add ecx, edi   ; ecx = ecx + edi
  54. :00401B2C 0FAFC8          imul ecx, eax  ; ecx = ecx * eax
  55. :00401B2F 40              inc eax        ; eax = eax + 1
  56. :00401B30 8BF9            mov edi, ecx   ; edi = ecx
  57. :00401B32 3BC6            cmp eax, esi   ; (eax - esi) (eax is the counter)
  58. :00401B34 76EF            jbe 00401B25   ; loop if eax <= esi(length)
  59.  
  60. :00401B36 33C9            xor ecx, ecx   ; ecx = 0;
  61. :00401B38 85F6            test esi, esi  ; (esi & esi)
  62. :00401B3A 7620            jbe 00401B5C   ; jump/quit if esi(length) is 0
  63.  
  64.                           ; [esp+14] points to the username
  65.                           ; [esp+48] points to the generated key
  66.                           ; ecx is the counter = 0 at start
  67.                           ; edi contains a key value from previous loop
  68. :00401B3C 0FBE6C0C14      movsx ebp, byte ptr [esp+ecx+14] ; ebp = user[ecx]
  69. :00401B41 8BC7            mov eax, edi       ; eax = edi (key)
  70. :00401B43 33D2            xor edx, edx       ; edx = 0
  71. :00401B45 F7F5            div ebp            ; eax = eax/ebp, edx = eax%ebp
  72. :00401B47 33D2            xor edx, edx       ; edx = 0
  73. :00401B49 BD0A000000      mov ebp, 0000000A  ; ebp = 0xA
  74. :00401B4E F7F5            div ebp            ; eax = eax/ebp, edx = eax%ebp
  75. :00401B50 80C230          add dl, 30         ; dl = dl + 0x30
  76. :00401B53 88540C48        mov byte ptr [esp+ecx+48], dl  ; key[ecx] = dl
  77. :00401B57 41              inc ecx            ; ecx = ecx + 1
  78. :00401B58 3BCE            cmp ecx, esi       ; (ecx - esi)
  79. :00401B5A 72E0            jb 00401B3C        ; loop if ecx < esi
  80.  
  81. :00401B5C 8D542448        lea edx, dword ptr [esp+48] ; -> generated key
  82. :00401B60 8D44247C        lea eax, dword ptr [esp+7C] ; -> password entered
  83. :00401B64 52              push edx  ; push pointer to key onto stack
  84. :00401B65 50              push eax  ; push pointer to password onto stack
  85.                           ; lstrcmpA compares the two string pushed onto stack
  86.                           ; the return value is stored in eax
  87.                           ; if two string equals, eax = 0
  88. :00401B66 FF1508404000    Call dword ptr [00404008]  ; KERNEL32.lstrcmpA
  89. :00401B6C 85C0            test eax, eax  ; (eax & eax)
  90. :00401B6E 7550            jne 00401BC0   ; jump if eax is not 0
  91.  
  92.  
  93. Now without looking at the solution, see if you can translate the above
  94. assembly code into a high level pseudo code.  Then compare the pseudo code
  95. to the actually codes (solution) below. Just to give you an idea of what 
  96. I mean by pseudo code, lets take a look at line :00401B25 to :00401B34 
  97. for an example.
  98. First off this is obviously a loop, because of the "JBE" instruction at
  99. line :00401B34.  This tells it to jump back to line :00401B25.  But what
  100. are the conditions for this loop?  Well, lets start from the beginning...
  101.  
  102. Start of code Anaylsis:
  103. This is the first line of the loop... 
  104.   :00401B25 0FBE4C0414      movsx ecx, byte ptr [esp+eax+14]
  105. You know that mov is just the same as '=' sign in high level language.
  106. And movsx is just a variant of mov, and the distinction between the two
  107. is not important here.  What you need to know is what this line of
  108. instruction is doing.  And when you see the bracket [], you know it's got
  109. something to do with the memory.  So you should spy on the memory a little
  110. and see what's up.  Just type in "d esp+eax+14" at Softice command window.
  111. All of a sudden you should see your username in the data window.  So
  112. obviously the above instruction is moving a character (byte) from the
  113. username into the ECX register!
  114.  
  115. Now lets look at the rest of the loop's content:
  116. (note that EAX was initialized to 1 at line :00401B1A)
  117. (also note that EDI was initialized to 0 at line :00401B1F)
  118.  
  119. add ecx, edi   ; add edi to ECX (ecx is the byte from username)
  120. imul ecx, eax  ; multiply ECX by eax (eax is the counter for this loop)
  121. inc eax        ; add one to EAX
  122. mov edi, ecx   ; save ecx to EDI (secret value!!!)
  123. cmp eax, esi   ; it modifies the zero & sign flag for comparison
  124. jbe 00401B25   ; loop if eax <= esi (esi is the length of the username)
  125.  
  126. The last two lines obviously tells you that EAX is indeed the counter.
  127. Because it is used to compare against ESI, which is the length of the
  128. username.  And how do you know that EDI stores the secret value?
  129. Well, you know it is not eax or esi.  You also know that it is not
  130. ecx, because ecx is changed at the first line when you move bytes from
  131. username to it.  And all you left with is edi, and it only involves in 
  132. mathmatical operations.  So edi must be it! The final value return/result
  133. from this loop!
  134. Also noticed that EAX gets incremented! This is use to move the character
  135. pointer along the string.  Each loop, this counter will points to the
  136. next character in the string.
  137.  
  138. Now you have enough information to write your first pseudo code!
  139.  
  140. i = 1
  141. finalvalue = 0
  142.  
  143. do
  144.   tmpvar = username(i)
  145.   tmpvar = tmpvar * i
  146.   i = i + 1
  147.   finalvalue = tmpvar
  148. repeat if i <= length of username
  149.  
  150. You are done!  The only thing left is to do the same with the rest of
  151. the registration routine, and then translate the pseudo codes into
  152. higher level language that you're familiar with, and modify the code
  153. a little to make it produce the registration key!
  154.  
  155.  
  156. Solution to the registration routine taken from my C++ source file.
  157. -------------------------------------------------------------------
  158.   register DWORD i, slen, sum;
  159.   char usrn[51] = "\0", key[51] = "\0", keystr[51] = "\0";
  160.  
  161.   GetDlgItemText(IDC_USRN, usrn, 51);
  162.   GetDlgItemText(IDC_KEY, key, 51);
  163.   if ((slen = lstrlen(usrn)) < 5)
  164.   {
  165.     MessageBox("User Name must have at least 5 characters.",
  166.     "CrackMe", MB_OK | MB_ICONINFORMATION);
  167.     return;
  168.   }
  169.   for (sum = 0, i = 1; i <= slen; i++)
  170.   {
  171.     sum += usrn[i];
  172.     sum *= i;
  173.   }
  174.   for (i = 0; i < slen; i++)
  175.     keystr[i] = LOBYTE( (sum / usrn[i]) % 10 + '0' );
  176.   if (lstrcmp(key, keystr) == 0)
  177.   {
  178.     // correct registration code! 
  179.   }
  180.   else
  181.   {
  182.     // incorrect registration code!
  183.   }
  184.  
  185. Sample of Key Generator
  186. -----------------------
  187. This is all you will need for the key generator, after translation.
  188. All you need to do is to display "keystr[]" to the user.
  189. There isn't much for you to modified from the original code in order
  190. to obtain the registration key.  You bascially just need to port
  191. part of the code and remove the remaining, and that's it.
  192.  
  193. for (sum = 0, i = 1; i <= slen; i++)
  194. {
  195.   sum += usrn[i];
  196.   sum *= i;
  197. }
  198. for (i = 0; i < slen; i++)
  199.   keystr[i] = LOBYTE( (sum / usrn[i]) % 10 + '0' );
  200.